/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 abstract_adv_actor.cpp

	$Header: /heroes4/abstract_adv_actor.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#pragma warning( disable: 4786 ) // Disable the ever so helpful "identifier was truncated to '255' characters" warning

#include "abstract_adv_actor.h"

#include <assert.h>
#include <stdlib.h>

#include "abstract_adv_object_visitor.h"
#include "adv_actor_model.h"
#include "adv_object_flag.h"
#include "adventure_tile_size.h"
#include "animation.h"
#include "animation_cache.h"
#include "owned_ptr.h"
#include "player_color.h"
#include "screen_point.h"

using namespace abstract_adv_actor_details;

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{
	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	typedef t_adv_object_flag t_flag_subimage;

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_animation_cache const k_highlight_animation_cache( "highlight_ring" );;

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_screen_point get_base_point( t_animation const & animation )
	{
		t_screen_rect rect = animation.get_rect();
		t_screen_point result = animation.get_base_point();
		if ( !animation.x_is_valid() )
			result.x = rect.left + ( rect.right - rect.left ) / 2;
		if ( !animation.y_is_valid() )
			result.y = rect.top + ( rect.bottom - rect.top ) / 2;
		return result;
	}

	// --------------------------------------------------------------------------
	// t_highlight_subimage class
	// --------------------------------------------------------------------------

	class t_highlight_subimage : public t_adv_object_subimage
	{
	public:
		// Constructor
		t_highlight_subimage();

		// Member functions
		int						compute_frame( t_uint32 time ) const;
		virtual void			draw_to(
									int						frame_num,
									t_screen_rect const &	source_rect,
									t_abstract_bitmap16 &	dest,
									t_screen_point const &	dest_point,
									int						alpha = 15 ) const;
		virtual void			draw_to(
									int						frame_num,
									t_abstract_bitmap16 &	dest,
									t_screen_point const &	dest_point ) const;
		virtual int				get_depth_offset() const;
		int						get_frame_count() const;					
		virtual t_screen_rect	get_rect() const;
		virtual t_screen_rect	get_rect( int frame_num ) const;
		bool					hit_test(
									int						frame_num,
									t_screen_point const &	point ) const;
		virtual bool			is_underlay() const;

	private:
		// Static member functions
		static t_screen_point const &	get_offset();

		// Data members
		t_cached_ptr< t_animation >	m_animation_ptr;
		t_screen_point				m_base_point;
		t_uint32					m_time_offset;

		// Member functions
		t_uint32	pick_time_offset() const;
	};

	// --------------------------------------------------------------------------
	// t_highlight_subimage members
	// --------------------------------------------------------------------------

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	inline t_screen_point const & t_highlight_subimage::get_offset()
	{
		static t_screen_point const k_offset( 0, k_adventure_tile_height / 2 );
		return k_offset;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_highlight_subimage::t_highlight_subimage()
		:	m_animation_ptr( k_highlight_animation_cache.get() ),
			m_base_point( get_base_point( *m_animation_ptr ) ),
			m_time_offset( pick_time_offset() )
	{
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	int t_highlight_subimage::compute_frame( t_uint32 time ) const
	{
		t_animation const & animation = *m_animation_ptr;
		return ( ( time + m_time_offset ) / animation.get_frame_delay() ) % animation.get_frame_count();
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	void t_highlight_subimage::draw_to(
		int						frame_num,
		t_screen_rect const &	source_rect,
		t_abstract_bitmap16 &	dest,
		t_screen_point const &	dest_point,
		int						alpha ) const
	{
		assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
		assert( m_animation_ptr->get_frame( frame_num ) != 0 );

		t_screen_point offset = get_offset() - m_base_point;
		t_screen_rect adjusted_source_rect = source_rect - offset;

		t_bitmap_layer const & frame = *m_animation_ptr->get_frame( frame_num );
		t_screen_rect const & frame_rect = frame.get_rect();

		if ( !intersect( adjusted_source_rect, frame_rect ) )
			return;

		adjusted_source_rect = intersection( adjusted_source_rect, frame_rect );

		frame.draw_to(
			adjusted_source_rect,
			dest,
			dest_point + offset + adjusted_source_rect.top_left(),
			alpha );
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	void t_highlight_subimage::draw_to(
		int						frame_num,
		t_abstract_bitmap16 &	dest,
		t_screen_point const &	dest_point ) const
	{
		assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
		assert( m_animation_ptr->get_frame( frame_num ) != 0 );

		m_animation_ptr->get_frame( frame_num )->draw_to(
			dest,
			dest_point + get_offset() - m_base_point );
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	int t_highlight_subimage::get_depth_offset() const
	{
		return -1;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	int t_highlight_subimage::get_frame_count() const
	{
		return m_animation_ptr->get_frame_count();
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_screen_rect t_highlight_subimage::get_rect() const
	{
		return m_animation_ptr->get_rect() + get_offset() - m_base_point;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_screen_rect t_highlight_subimage::get_rect( int frame_num ) const
	{
		assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
		assert( m_animation_ptr->get_frame( frame_num ) != 0 );
		return m_animation_ptr->get_frame( frame_num )->get_rect() + get_offset() - m_base_point;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	bool t_highlight_subimage::hit_test(
		int						frame_num,
		t_screen_point const &	point ) const
	{
		assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
		assert( m_animation_ptr->get_frame( frame_num ) != 0 );

		return m_animation_ptr->get_frame( frame_num )->contains( point - get_offset() + m_base_point );
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	bool t_highlight_subimage::is_underlay() const
	{
		return false;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_uint32 t_highlight_subimage::pick_time_offset() const
	{
		t_animation const & animation = *m_animation_ptr;
		return rand() % ( animation.get_frame_count() * animation.get_frame_delay() );
	}

	// --------------------------------------------------------------------------
	// Non-member functions
	// --------------------------------------------------------------------------

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	template < typename t_subimage >
	void draw_subimage_helper(
		t_abstract_adv_actor const &	actor,
		t_subimage const &				subimage,
		t_uint32						current_time,
		t_screen_rect const &			source_rect,
		t_abstract_bitmap16 &			dest,
		t_screen_point const &			dest_point,
		int								alpha = 15 )
	{
		t_screen_point frame_offset = actor.get_frame_offset();
		subimage.draw_to(
			subimage.compute_frame( current_time ),
			source_rect - frame_offset,
			dest,
			dest_point + frame_offset,
			alpha );
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	template < typename t_subimage >
	void draw_subimage_helper(
		t_abstract_adv_actor const &	actor,
		t_subimage const &				subimage,
		t_uint32						current_time,
		t_abstract_bitmap16 &			dest,
		t_screen_point const &			dest_point )
	{
		t_screen_point frame_offset = actor.get_frame_offset();
		subimage.draw_to(
			subimage.compute_frame( current_time ),
			dest,
			dest_point + frame_offset );
	}

} // Unnamed namespace

// --------------------------------------------------------------------------
// Details namespace
// --------------------------------------------------------------------------

namespace abstract_adv_actor_details
{

	// --------------------------------------------------------------------------
	// t_impl class
	// --------------------------------------------------------------------------

	class t_impl
	{
	public:
		// Data members
		t_player_color						m_flag_color;
		t_owned_ptr< t_flag_subimage >		m_flag_subimage_ptr;
		t_owned_ptr< t_highlight_subimage >	m_highlight_subimage_ptr;

		// Constructor
		t_impl();
		t_impl( t_impl const & other );

		// Operator
		t_impl & operator=( t_impl const & other );
	};

	// --------------------------------------------------------------------------
	// t_impl members
	// --------------------------------------------------------------------------

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	inline t_impl::t_impl()
		:	m_flag_color( k_player_gray )
	{
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_impl::t_impl( t_impl const & other )
		:	m_flag_color( other.m_flag_color )
	{
		if ( other.m_flag_subimage_ptr.get() != 0 )
			m_flag_subimage_ptr.reset( new t_flag_subimage( *other.m_flag_subimage_ptr ) );

		if ( other.m_highlight_subimage_ptr.get() != 0 )
			m_highlight_subimage_ptr.reset( new t_highlight_subimage( *other.m_highlight_subimage_ptr ) );
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_impl & t_impl::operator=( t_impl const & other )
	{
		t_owned_ptr< t_flag_subimage > new_flag_subimage_ptr;
		t_owned_ptr< t_highlight_subimage > new_highlight_subimage_ptr;

		if ( other.m_flag_subimage_ptr.get() != 0 )
			new_flag_subimage_ptr.reset( new t_flag_subimage( *other.m_flag_subimage_ptr ) );

		if ( other.m_highlight_subimage_ptr.get() != 0 )
			new_highlight_subimage_ptr.reset( new t_highlight_subimage( *other.m_highlight_subimage_ptr ) );

		m_flag_color = other.m_flag_color;
		m_flag_subimage_ptr.swap( new_flag_subimage_ptr );
		m_highlight_subimage_ptr.swap( new_highlight_subimage_ptr );

		return *this;
	}

} // Details namespace

// --------------------------------------------------------------------------
// t_abstract_adv_actor members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_abstract_adv_actor::t_abstract_adv_actor()
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_abstract_adv_actor::t_abstract_adv_actor(
	t_abstract_adv_actor const &	other )
	:	m_impl_ptr( other.m_impl_ptr )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_abstract_adv_actor::~t_abstract_adv_actor()
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::accept( t_visitor & visitor )
{
	visitor.visit( *this );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::accept( t_visitor & visitor ) const
{
	visitor.visit( *this );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::animates() const
{
	if ( do_animates() )
		return true;

	t_flag_subimage const * flag_subimage_ptr = m_impl_ptr->m_flag_subimage_ptr.get();
	if ( flag_subimage_ptr != 0 && flag_subimage_ptr->get_frame_count() > 1 )
		return true;

	t_highlight_subimage const * highlight_subimage_ptr = m_impl_ptr->m_highlight_subimage_ptr.get();
	return highlight_subimage_ptr != 0 && highlight_subimage_ptr->get_frame_count() > 1;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::draw_subimage_to(
	int						subimage_num,
	t_uint32				current_time,
	t_screen_rect const &	source_rect, 
	t_abstract_bitmap16 &	dest, 
	t_screen_point const &	dest_point,
	int						alpha ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
		{
			draw_subimage_helper(
				*this,
				*impl.m_highlight_subimage_ptr,
				current_time,
				source_rect,
				dest,
				dest_point,
				alpha );
			return;
		}
		--subimage_num;
	}

	if ( subimage_num == 0 )
		do_draw_to( current_time, source_rect, dest, dest_point, alpha );
	else
	{
		assert( subimage_num == 1 );
		assert( impl.m_flag_subimage_ptr.get() != 0 );

		draw_subimage_helper(
			*this,
			*impl.m_flag_subimage_ptr,
			current_time,
			source_rect,
			dest,
			dest_point,
			alpha );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::draw_subimage_to(
	int						subimage_num,
	t_uint32				current_time, 
	t_abstract_bitmap16 &	dest, 
	t_screen_point const &	dest_point ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
		{
			draw_subimage_helper(
				*this,
				*impl.m_highlight_subimage_ptr,
				current_time,
				dest,
				dest_point );
			return;
		}
		--subimage_num;
	}

	if ( subimage_num == 0 )
		do_draw_to( current_time, dest, dest_point );
	else
	{
		assert( subimage_num == 1 );
		assert( impl.m_flag_subimage_ptr.get() != 0 );

		draw_subimage_helper(
			*this,
			*impl.m_flag_subimage_ptr,
			current_time,
			dest,
			dest_point );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::draw_to(
	t_uint32				current_time, 
	t_screen_rect const &	source_rect,
	t_abstract_bitmap16 &	dest, 
	t_screen_point const &	dest_point ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		draw_subimage_helper(
			*this,
			*impl.m_highlight_subimage_ptr,
			current_time,
			source_rect,
			dest,
			dest_point );
	}
	
	do_draw_to( current_time, source_rect, dest, dest_point );

	if ( impl.m_flag_subimage_ptr.get() != 0 )
	{
		draw_subimage_helper(
			*this,
			*impl.m_flag_subimage_ptr,
			current_time,
			source_rect,
			dest,
			dest_point );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::draw_to(
	t_uint32				current_time, 
	t_abstract_bitmap16 &	dest, 
	t_screen_point const &	dest_point ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		draw_subimage_helper(
			*this,
			*impl.m_highlight_subimage_ptr,
			current_time,
			dest,
			dest_point );
	}

	do_draw_to( current_time, dest, dest_point );

	if ( impl.m_flag_subimage_ptr.get() != 0 )
	{
		draw_subimage_helper(
			*this,
			*impl.m_flag_subimage_ptr,
			current_time,
			dest,
			dest_point );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::enable_highlight( bool enable )
{
	t_impl & impl = *m_impl_ptr;
	if ( enable )
	{
		if ( impl.m_highlight_subimage_ptr.get() == 0 )
			impl.m_highlight_subimage_ptr.reset( new t_highlight_subimage );
	}
	else
	{
		if ( impl.m_highlight_subimage_ptr.get() != 0 )
			impl.m_highlight_subimage_ptr.reset();
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_footprint const & t_abstract_adv_actor::get_footprint() const
{
	return get_model();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_point t_abstract_adv_actor::get_frame_offset() const
{
	return t_screen_point( 0, 0 );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_abstract_adv_actor::get_rect() const
{
	t_screen_rect result = do_get_rect();

	t_flag_subimage const * flag_subimage_ptr = m_impl_ptr->m_flag_subimage_ptr.get();
	if ( flag_subimage_ptr != 0 )
	{
		result =
			get_extent( result, flag_subimage_ptr->get_rect() + get_frame_offset() );
	}

	t_highlight_subimage const * highlight_subimage_ptr = m_impl_ptr->m_highlight_subimage_ptr.get();
	if ( highlight_subimage_ptr != 0 )
	{
		result =
			get_extent( result, highlight_subimage_ptr->get_rect() + get_frame_offset() );
	}

	return result;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_abstract_adv_actor::get_rect( t_uint32 current_time ) const
{
	t_screen_rect result = do_get_rect( current_time );

	t_flag_subimage const * flag_subimage_ptr = m_impl_ptr->m_flag_subimage_ptr.get();
	if ( flag_subimage_ptr != 0 )
	{
		int frame_num = flag_subimage_ptr->compute_frame( current_time );
		result =
			get_extent( result, flag_subimage_ptr->get_rect( frame_num ) + get_frame_offset() );
	}

	t_highlight_subimage const * highlight_subimage_ptr = m_impl_ptr->m_highlight_subimage_ptr.get();
	if ( highlight_subimage_ptr != 0 )
	{
		int frame_num = highlight_subimage_ptr->compute_frame( current_time );
		result =
			get_extent( result, highlight_subimage_ptr->get_rect( frame_num ) + get_frame_offset() );
	}

	return result;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_abstract_adv_actor::get_subimage_count() const
{
	t_impl const & impl = *m_impl_ptr;
	return		1
			+	( impl.m_flag_subimage_ptr.get() != 0 )
			+	( impl.m_highlight_subimage_ptr.get() != 0 );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_abstract_adv_actor::get_subimage_depth_offset( int subimage_num ) const
{
	assert( subimage_num >= 0 && subimage_num < get_subimage_count() );
	return -get_model().get_footprint_size();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_abstract_adv_actor::get_subimage_rect( int subimage_num ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
			return impl.m_highlight_subimage_ptr->get_rect() + get_frame_offset();
		--subimage_num;
	}

	if ( subimage_num == 0 )
		return do_get_rect();

	assert( subimage_num == 1 );
	assert( impl.m_flag_subimage_ptr.get() != 0 );

	return impl.m_flag_subimage_ptr->get_rect() + get_frame_offset();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_abstract_adv_actor::get_subimage_rect(
	int			subimage_num,
	t_uint32	time ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
		{
			t_highlight_subimage const & highlight_subimage = *impl.m_highlight_subimage_ptr;
			int frame_num = highlight_subimage.compute_frame( time );
			return highlight_subimage.get_rect( frame_num ) + get_frame_offset();
		}
		--subimage_num;
	}

	if ( subimage_num == 0 )
		return do_get_rect( time );

	assert( subimage_num == 1 );
	assert( impl.m_flag_subimage_ptr.get() != 0 );

	t_flag_subimage const & flag_subimage = *impl.m_flag_subimage_ptr;
	int frame_num = flag_subimage.compute_frame( time );
	return flag_subimage.get_rect( frame_num ) + get_frame_offset();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::hit_test(
	t_uint32				current_time,
	t_screen_point const &	point ) const
{
	if ( do_hit_test( current_time, point ) )
		return true;

	t_impl const & impl = *m_impl_ptr;

	t_flag_subimage const * flag_subimage_ptr = impl.m_flag_subimage_ptr.get();
	if ( flag_subimage_ptr != 0 )
	{
		int frame_num = flag_subimage_ptr->compute_frame( current_time );
		if ( flag_subimage_ptr->hit_test( frame_num, point - get_frame_offset() ) )
			return true;
	}

	t_highlight_subimage const * highlight_subimage_ptr = impl.m_highlight_subimage_ptr.get();
	if ( highlight_subimage_ptr == 0 )
		return false;

	int frame_num = highlight_subimage_ptr->compute_frame( current_time );
	return highlight_subimage_ptr->hit_test( frame_num, point - get_frame_offset() );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::is_highlighted() const
{
	return m_impl_ptr->m_highlight_subimage_ptr.get() != 0;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::needs_redrawing(
	t_uint32	last_update_time,
	t_uint32	current_time ) const
{
	if ( do_needs_redrawing( last_update_time, current_time ) )
		return true;

	t_impl const & impl = *m_impl_ptr;

	t_flag_subimage const * flag_subimage_ptr = impl.m_flag_subimage_ptr.get();
	if (	flag_subimage_ptr != 0
		&&		flag_subimage_ptr->compute_frame( last_update_time )
			!=	flag_subimage_ptr->compute_frame( current_time ) )
		return true;

	t_highlight_subimage const * highlight_subimage_ptr = impl.m_highlight_subimage_ptr.get();
	return		highlight_subimage_ptr != 0
			&&		highlight_subimage_ptr->compute_frame( last_update_time )
				!=	highlight_subimage_ptr->compute_frame( current_time );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::subimage_animates( int subimage_num ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
			return impl.m_highlight_subimage_ptr->get_frame_count() > 1;
		--subimage_num;
	}

	if ( subimage_num == 0 )
		return do_animates();

	assert( subimage_num == 1 );
	assert( impl.m_flag_subimage_ptr.get() != 0 );

	return impl.m_flag_subimage_ptr->get_frame_count() > 1;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::subimage_is_underlay( int subimage_num ) const
{
	assert( subimage_num >= 0 && subimage_num < get_subimage_count() );
	return false;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::subimage_needs_redrawing(
	int			subimage_num,
	t_uint32	last_update_time,
	t_uint32	current_time ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
		{
			t_highlight_subimage const & highlight_subimage = *impl.m_highlight_subimage_ptr;
			return		highlight_subimage.compute_frame( last_update_time )
					!=	highlight_subimage.compute_frame( current_time );
		}
		--subimage_num;
	}

	if ( subimage_num == 0 )
		return do_needs_redrawing( last_update_time, current_time );

	assert( subimage_num == 1 );
	assert( impl.m_flag_subimage_ptr.get() != 0 );

	t_flag_subimage const & flag_subimage = *impl.m_flag_subimage_ptr;
	return		flag_subimage.compute_frame( last_update_time )
			!=	flag_subimage.compute_frame( current_time );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_abstract_adv_actor & t_abstract_adv_actor::operator=(
	t_abstract_adv_actor const &	other )
{
	m_impl_ptr = other.m_impl_ptr;
	return *this;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::on_model_changed()
{
	t_impl const & impl = *m_impl_ptr.get_const();
	if ( impl.m_flag_color != k_player_gray )
	{
		assert( impl.m_flag_subimage_ptr.get() != 0 );

		t_model const & model = get_model();
		int depth_offset = -model.get_footprint_size();

		m_impl_ptr->m_flag_subimage_ptr.reset(
			new t_flag_subimage( impl.m_flag_color, model.get_flag_offset(), depth_offset ) );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_abstract_adv_actor::set_flag_color( t_player_color new_flag_color )
{
	assert( new_flag_color >= 0 && new_flag_color < k_player_color_count );

	if ( new_flag_color == m_impl_ptr.get_const()->m_flag_color )
		return;

	t_owned_ptr< t_flag_subimage >	new_flag_subimage_ptr;
	if ( new_flag_color != k_player_gray )
	{
		t_model const & model = get_model();
		int depth_offset = -model.get_footprint_size();
		new_flag_subimage_ptr.reset(
			new t_flag_subimage( new_flag_color, model.get_flag_offset(), depth_offset ) );
	}

	t_impl & impl = *m_impl_ptr;
	impl.m_flag_color = new_flag_color;
	impl.m_flag_subimage_ptr.swap( new_flag_subimage_ptr );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::visible_through_obstacles( int subimage_num ) const
{
	t_impl const & impl = *m_impl_ptr;

	if ( impl.m_highlight_subimage_ptr.get() != 0 )
	{
		if ( subimage_num == 0 )
			return false;
		--subimage_num;
	}

	if ( subimage_num == 0 )
		return do_visible_through_obstacles();

	assert( subimage_num == 1 );
	assert( impl.m_flag_subimage_ptr.get() != 0 );

	return false;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_abstract_adv_actor::do_visible_through_obstacles() const
{
	return false;
}
